﻿ /****---------------------------------------------------------------------------------------------------->>>>
*	Trace for Flash 8 [v1.0]
*	Coded to work with ActionScript 2.0
*	--------------------------------------------------
*	Created by
*		Lance Den (vistaden@msn.com , yanjun@vika.cn)
*		SIAN Digital Technology co.,ltd. (www.vika.cn)
*
*	Based on code by
*		(null)
*
*	Version History:
*		2007-04-20 - Estabished by Lance Den.
*
*	Authors notes:
*		Class Initialization:
*			- this is a Private Class
*
*			Example:
*				null
*
*			Note:
*				null
*
*			Example:
*				
*
*		- Lance Den 2007-06-21
<<<<----------------------------------------------------------------------------------------------------****/

import utils.Delegate;

class utils.Trace extends MovieClip
{
	private static var mc_target:MovieClip;
	private static var str_servicename:String;
	private static var trace_instance:Trace;
	
	private var lc_sender:LocalConnection;
	private var str_targeturl:String;
	
	// for decode check
	private var length;
	private var serializeValue;
	
	/*------------------------------------------------------------------------>
	* Constructor and Initialization
	<------------------------------------------------------------------------*/
	function Trace ()
	{
		this.initClass();
	}
	
	private function initClass():Void
	{
		Object.prototype.toString = this.toFormatedString;
		Object.prototype.serializeValue = this.toSerializeValue;
		MovieClip.prototype.echo = this.echoTrace;
		
		this.setAccessible(Object.prototype,"serializeValue",false,false,false);
		this.setAccessible(MovieClip.prototype,"echo",false,false,false);
		
		this.lc_sender = new LocalConnection();
		
		this.str_targeturl = Trace.mc_target._url;
		
		this.callRegister();
	}
	
	/*------------------------------------------------------------------------>
	* public static
	<------------------------------------------------------------------------*/
	public static function initialize(target:MovieClip):Void
	{
		if(target==undefined) target = _root;
		Trace.mc_target = target;
		// for future, run a function to generate a unique name string
		Trace.str_servicename = "_trace_win32_20070720";
		Trace.getInstance();
	};
	
	public static function getInstance():Trace
	{
		if(Trace.trace_instance == undefined)
		{
			Trace.trace_instance = new Trace();
		}
		return Trace.trace_instance;
	}
	
	public static function copyLowObject(obj_low):Object
	{
		var obj_tmp = new Object();
		for(var i in obj_low) obj_tmp[i] = obj_low[i];
		return obj_tmp;
	}
	
	/*------------------------------------------------------------------------>
	* public
	<------------------------------------------------------------------------*/
	public function sendTrace(str_t:String)
	{
		this.callTrace(str_t);
	};
	
	/*------------------------------------------------------------------------>
	* private -- prototype
	<------------------------------------------------------------------------*/
	private function setAccessible(obj:Object, field, write:Boolean, del:Boolean, visible:Boolean):Void {
		var w = write ? 0 : 4;
		var d = del   ? 0 : 2;
		var hide = visible ? 0 : 1;
		_global.ASSetPropFlags(obj, field, w+d+hide, true);
	}
	
	private function toFormatedString(s, t):String
	{
		var str_tmp:String = "";
		var str_w32:String = "";
		
		/*[20070722]
		if (t == undefined) t = "\t";
		else t += "\t";
		if (s == undefined) s = "Object: {";
		else s += "{";
		for (var p in this){
			s += "\n"+t;
			if (this[p] instanceof Array)  s += p+": ["+this[p]+"]";
			else if (typeof this[p]  == "object") s += this[p].toString(p+": ", t);
			else if (typeof this[p]  == "function") s += p+": (function)";
			else s += p+": "+this[p];
		}
		str_tmp = (s+"\n"+t.slice(0,-1)+"}");
		*/
		
		str_tmp = this.serializeValue(null,null,"");
		str_w32 = this.serializeValue();
		
		Trace.getInstance().sendTrace(str_w32);
		
		return str_tmp;
	}
	
	private function echoTrace(obj){
		var str_tmp:String = "";
		var str_w32:String = "";
		var obj_tmp:Object = new Object();
		
		// for MovieClip.getBounds() exchange
		if(typeof(obj)=="object" && obj.__proto__.constructor==undefined)
		{
			obj = Trace.copyLowObject(obj);
		}
		
		str_tmp = obj.serializeValue(null,null,"");
		trace(str_tmp);
		
		str_w32 = obj.serializeValue();
		Trace.getInstance().sendTrace(str_w32);
	}

	private function toSerializeValue(s, t, n) {
		var obj = this;
		var val:String = obj.valueOf();
		if(s==undefined) s="";
		if(n==undefined) n="\n";
		
		if (obj == null)
		{
			s = "Null"+n;
		}
		else if (typeof (val) == "string")
		{
			s = "String : "+obj+n;
		}
		else if (typeof (val) == "number")
		{
			if (typeof (obj.getTimezoneOffset) == "function") s += "Date : "+obj+n;
			else s += "Number : "+obj+n;
		}
		else if (typeof (val) == "boolean")
		{
			s = "Boolean : "+obj+n;
		}
		else if (typeof (val) == "movieclip")
		{
			s = "Movieclip : "+obj+n;
		}
		else if (typeof (val) == "function")
		{
			//[20070730] s = "Function : "+obj+n;
			s = "Fucntion : It is a function(){...}."+n;
		}
		else if (typeof (obj) == "object")
		{
			if (typeof (obj.join) == "function" && typeof (obj.reverse) == "function") {
				//  array object
				if (t == undefined) t = "\t";
				else t += "\t";
				if (s == undefined) s = "Array: ["+"\n";
				else s += "Array: ["+"\n";
				for (var p=0;p<this.length;p++) {
					//[20070722] if (p == "serializeValue") continue;
					//[20070722] s += "\n"+t;
					s += t;
					if (this[p] instanceof Array)  s += this[p].serializeValue("["+p+"] -> ", t);
					else if (typeof this[p]  == "object")
					{
						if(this[p].__proto__.constructor==undefined)
						{
							this[p] = Trace.copyLowObject(this[p]);
						}
						s += this[p].serializeValue("["+p+"] -> ", t);
					}
					else
					{
						if(this[p]==undefined) s += ("["+p+"] -> undefined"+"\n");
						else s += ("["+p+"] -> "+this[p].serializeValue());
					}
				}
				//[20070722] s = (s+"\n"+t.slice(0,-1)+"]");
				s = (s+t.slice(0,-1)+"]"+n);
			}
			else
			{
				if (t == undefined) t = "\t";
				else t += "\t";
				if (s == undefined) s = "Object: {"+"\n";
				else s += "Object: {"+"\n";
				for (var q in this) {
					//[20070722] if (q == "serializeValue") continue;
					//[20070722] s += "\n"+t;
					s += t;
					if (this[q] instanceof Array)  s += this[q].serializeValue("["+q+"] -> ", t);
					else if (typeof this[q]  == "object")
					{
						if(this[q].__proto__.constructor==undefined)
						{
							this[q] = Trace.copyLowObject(this[q]);
						}
						s += this[q].serializeValue("["+q+"] -> ", t);
					}
					else
					{
						if(this[q]==undefined) s += ("["+q+"] -> undefined"+"\n");
						else s += ("["+q+"] -> "+this[q].serializeValue());
					}
				}
				//[20070722] s = (s+"\n"+t.slice(0,-1)+"}");
				s = (s+t.slice(0,-1)+"}"+n);
			}
		}
		else
		{
			s = "Null"+n;
		}
		return s;
	}
	
	/*------------------------------------------------------------------------>
	* private -- call lc func
	<------------------------------------------------------------------------*/
	private function callRegister():Void
	{
		this.lc_sender.send(Trace.str_servicename, "register", {label:this.str_targeturl});
	}
	
	private function callTrace(str_t:String):Void
	{
		this.lc_sender.send(Trace.str_servicename, "trace", {label:this.str_targeturl,data:str_t});
	}
	
}